#include "fonte.h"

#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
#include <map>
#include <fstream>
#include <iostream>

using namespace std;

/******************************************************************************
    Este namespace serve para gerenciar as fontes e textos do jogo
******************************************************************************/
namespace Fonte{
    //Fonte padrao caso nenhuma seja especificada
	std::string DefaultFont;
	
	//Mapa das fontes instanciadas
	map<string, TTF_Font*> m_Fonts;
	typedef map<string, TTF_Font*>::iterator FontIterator;


/******************************************************************************
    Get(chave)
    Obtem uma fonte previamente estanciada no mapa
******************************************************************************/
	TTF_Font* Get(std::string chave){
		FontIterator pos = m_Fonts.find(chave);
		if (pos == m_Fonts.end()) return NULL;
		return pos->second;
	}

/******************************************************************************
    Descarregar(fonte)
    Destroi uma fonte instanciada para liberar memoria
******************************************************************************/
	void Descarregar(TTF_Font* font){
		if(font != NULL){
			TTF_CloseFont(font);
			font = NULL;
		}
	}

/******************************************************************************
    Descarregar(chave)
    Destroi uma fonte instanciada para liberar memoria
******************************************************************************/
	void Descarregar(std::string chave){
		Descarregar(Get(chave));
		FontIterator pos = m_Fonts.find(chave);
		if (pos == m_Fonts.end()) return;
		m_Fonts.erase(pos);
	}

/******************************************************************************
    Inicializa()
    Inicializa o SDL_ttf
******************************************************************************/
	bool Inicializa(){
		if(TTF_Init() == -1)
			return false;
		return true;
	}

/******************************************************************************
    Finaliza()
    Destroi todas as fonte, liberando memoria e finaliza o SDL_ttf
******************************************************************************/
	void Finaliza() {
		for(FontIterator pos = m_Fonts.begin(); pos != m_Fonts.end(); ++pos){
			Descarregar(pos->second);
    	}
		TTF_Quit();
	}

/******************************************************************************
    Carregar(chave, arquivo, tamanho)
    Instancia uma nova fonte na memoria
******************************************************************************/
	bool Carregar(std::string key, std::string filename, int fontSize){
		fstream fin;
		fin.open(filename.c_str(),ios::in);
		if(fin.is_open()){ //Arquivo existe?
			fin.close();
			TTF_Font* font = TTF_OpenFont(filename.c_str(), fontSize);
			if(font == NULL){
				cerr << "TTF get font: " << TTF_GetError();
				return false;
			}
			m_Fonts[key] = font;
			DefaultFont = key;
			return true;
		}
		fin.close();
		return false;
	}
	
/******************************************************************************
    CriarSuperficie(texto, fonte, cor rgb)
    Cria uma nova superficie onde sera desenhado o texto
******************************************************************************/
	SDL_Surface* CriarSuperficie(std::string texto, TTF_Font* fonte, int r, int g, int b){
		SDL_Surface* txtSurface;
		SDL_Color cor = {r,g,b,0};
		if(!(txtSurface = TTF_RenderText_Solid(fonte,texto.c_str(), cor))){
			cerr << "TTF print: " << TTF_GetError();
			if(txtSurface != NULL)
				SDL_FreeSurface(txtSurface);
			return NULL;
		}
		return txtSurface;
	}

/******************************************************************************
    CriarSuperficie(texto, fonte, cor rgb)
    Cria uma nova superficie onde sera desenhado o texto
******************************************************************************/
	SDL_Surface* CriarSuperficie(char *texto, TTF_Font* fonte, int r, int g, int b){
		SDL_Surface* txtSurface;
		SDL_Color cor = {r,g,b,0};
		if(!(txtSurface = TTF_RenderText_Solid(fonte,texto, cor))){
			cerr << "TTF print: " << TTF_GetError();
			if(txtSurface != NULL)
				SDL_FreeSurface(txtSurface);
			return NULL;
		}
		return txtSurface;
	}
	

/******************************************************************************
    Altura(chave)
    Retorna a altura de uma fonte
******************************************************************************/
	int Altura(std::string chave){
		TTF_Font *fonte = Get(chave);
		if(fonte != NULL) return TTF_FontHeight(fonte);
		return 0;
	}

/******************************************************************************
    Print(pos, texto, cor, alinhamento, chave, tela)
    Desenha o texto na tela.
******************************************************************************/
	bool Print( int x, int y,  //Posicao
                std::string texto, //Texto
                int r, int g, int b, //Cor da fonte
                int halign, int valign, //Alinhamento
                std::string chave, //Chave
                SDL_Surface *tela) //Tela onde desenhar
        {

		//Encontrar a fonte
		TTF_Font* FontTTF;
		if(chave == "default")
			FontTTF = Get(DefaultFont);
		else
			FontTTF = Get(chave);
		if(FontTTF == NULL){ // Escolhe qualquer fonte como default
			for(FontIterator pos = m_Fonts.begin(); pos != m_Fonts.end(); ++pos){
				FontTTF = Get(pos->first);
				if(FontTTF != NULL)
					break;
	    	}
		}
		if(FontTTF == NULL)	return false; // Sai se nao houver fonte

		// Cria uma superficie com o texto
		SDL_Surface* txtSurface = CriarSuperficie(texto, FontTTF,r,g,b);
		if(txtSurface != NULL){
			SDL_Rect dest;
			switch(halign){
			case 1: // hAlign = Central
				dest.x = x - (int)(txtSurface->w/2);
				break;
			case 2: // hAlign = Right
				dest.x = x - (int)txtSurface->w;
				break;
			default: // hAlign = Left
		    	dest.x = x;
			}
			switch(valign){
			case 1: // vAlign = Center
				dest.y = y - (int)(txtSurface->h/2);
				break;
			case 2: // vAlign = Bottom
				dest.y = y - (int)txtSurface->h;
				break;
			default: // vAlign = Top
				dest.y = y;
			}

		    SDL_BlitSurface(txtSurface, NULL, tela, &dest);
			SDL_FreeSurface(txtSurface);
			return true;
		} else {
			return false;
		}
	}


/******************************************************************************
    Print(pos, texto, cor, alinhamento, chave, tela)
    Desenha o texto na tela.
******************************************************************************/
	bool Print( int x, int y,  //Posicao
                char *texto, //Texto
                int r, int g, int b, //Cor da fonte
                int halign, int valign, //Alinhamento
                std::string chave, //Chave
                SDL_Surface *tela) //Tela onde desenhar
        {

		//Encontrar a fonte
		TTF_Font* FontTTF;
		if(chave == "default")
			FontTTF = Get(DefaultFont);
		else
			FontTTF = Get(chave);
		if(FontTTF == NULL){ // Escolhe qualquer fonte como default
			for(FontIterator pos = m_Fonts.begin(); pos != m_Fonts.end(); ++pos){
				FontTTF = Get(pos->first);
				if(FontTTF != NULL)
					break;
	    	}
		}
		if(FontTTF == NULL)	return false; // Sai se nao houver fonte

		// Cria uma superficie com o texto
		SDL_Surface* txtSurface = CriarSuperficie(texto, FontTTF,r,g,b);
		if(txtSurface != NULL){
			SDL_Rect dest;
			switch(halign){
			case 1: // hAlign = Central
				dest.x = x - (int)(txtSurface->w/2);
				break;
			case 2: // hAlign = Right
				dest.x = x - (int)txtSurface->w;
				break;
			default: // hAlign = Left
		    	dest.x = x;
			}
			switch(valign){
			case 1: // vAlign = Center
				dest.y = y - (int)(txtSurface->h/2);
				break;
			case 2: // vAlign = Bottom
				dest.y = y - (int)txtSurface->h;
				break;
			default: // vAlign = Top
				dest.y = y;
			}

		    SDL_BlitSurface(txtSurface, NULL, tela, &dest);
			SDL_FreeSurface(txtSurface);
			return true;
		} else {
			return false;
		}
	}
}
